/********************************************************************
	created:	30:9:2007   19:35
	author:		tiamo
	purpose:	add device
*********************************************************************/

#include "stdafx.h"

#ifdef ALLOC_PRAGMA
  #pragma alloc_text(PAGE,AppleKeyboardAddDevice)
#endif

// keyboard count
LONG																	g_lKeyboardCount = 0;

// add device
NTSTATUS AppleKeyboardAddDevice(__in PDRIVER_OBJECT pDriverObject,__in PDEVICE_OBJECT pPhysicalDeviceObject)
{
	PAGED_CODE();

	NTSTATUS statusRet = STATUS_SUCCESS;
	PDEVICE_OBJECT pFunctionDeviceObject = 0;
	CDeviceExtension* pDevExt = 0;
	BOOLEAN bDeleteDevice = FALSE;
	BOOLEAN bDetachDevice = FALSE;

	//C_ASSERT(sizeof(CDeviceExtension) == 0x200);
	
	AppleDebugPrint(DBGLEVEL_INFO,"Enter AppleKeyboardAddDevice %p,%p\n",pDriverObject,pPhysicalDeviceObject);

	__try
	{
		statusRet = IoCreateDevice(pDriverObject,sizeof(CDeviceExtension),0,FILE_DEVICE_KEYBOARD,0,FALSE,&pFunctionDeviceObject);
		if(!NT_SUCCESS(statusRet))
			__leave;

		bDeleteDevice = TRUE;
		pDevExt = static_cast<CDeviceExtension*>(pFunctionDeviceObject->DeviceExtension);
		pDevExt->m_pLowerDevice = IoAttachDeviceToDeviceStack(pFunctionDeviceObject,pPhysicalDeviceObject);
		if(!pDevExt->m_pLowerDevice)
		{
			AppleDebugPrint(DBGLEVEL_ERROR,"ERROR: AppleKeyboard unable to attack device stack\n");
			statusRet = STATUS_DEVICE_NOT_CONNECTED;
			__leave;
		}

		bDetachDevice = TRUE;
		pDevExt->m_pFunctionDeviceObject = pFunctionDeviceObject;
		pDevExt->m_pPhysicalDeviceObject = pPhysicalDeviceObject;
		pDevExt->m_bDeviceStarted = FALSE;
		pDevExt->m_bLowerKeyboardDeviceStarted = FALSE;
		pDevExt->m_usUnitId = static_cast<USHORT>(InterlockedIncrement(&g_lKeyboardCount));
		KeInitializeSpinLock(&pDevExt->m_spinLockUsageMappings);
		pDevExt->m_pReadIrp = IoAllocateIrp(pDevExt->m_pLowerDevice->StackSize,0);
		if(!pDevExt->m_pReadIrp)
		{
			AppleDebugPrint(DBGLEVEL_ERROR,"ERROR: AppleKeyboard unable to allocate read irp\n");
			statusRet = STATUS_INSUFFICIENT_RESOURCES;
			__leave;
		}

		KeInitializeEvent(&pDevExt->m_eventPingPongStopped,SynchronizationEvent, FALSE);
		KeInitializeEvent(&pDevExt->m_eventReadComplete,NotificationEvent,TRUE);

		IoInitializeRemoveLock(&pDevExt->m_removeLock,'Appl',1,10);

		ExInitializeFastMutex(&pDevExt->m_fastMutex);

		pDevExt->m_pReadFileObject = 0;
		pDevExt->m_attributeKeyboard.KeyRepeatMaximum.UnitId = pDevExt->m_usUnitId;
		pDevExt->m_attributeKeyboard.KeyRepeatMinimum.UnitId = pDevExt->m_usUnitId;
		pDevExt->m_dataKeyboardInput.UnitId = pDevExt->m_usUnitId;
		pDevExt->m_paramTypematic.UnitId = pDevExt->m_usUnitId;
		pDevExt->m_paramIndicator.UnitId = pDevExt->m_usUnitId;
		pDevExt->m_dataKeyboardInput.MakeCode = 0;
		pDevExt->m_dataKeyboardInput.Flags = 0;
		pDevExt->m_ulScanCodesState = 0;
		pDevExt->m_attributeKeyboard.KeyboardIdentifier.Type = 0x51/*KEYBOARD_TYPE_UNKNOWN*/;
		pDevExt->m_attributeKeyboard.KeyboardIdentifier.Subtype = 0;
		pDevExt->m_attributeKeyboard.KeyboardMode = 1;
		pDevExt->m_wmiKeyboardIdEx.Type = 0x51/*KEYBOARD_TYPE_UNKNOWN*/;
		pDevExt->m_wmiKeyboardIdEx.Subtype = 0;
		pDevExt->m_attributeKeyboard.NumberOfFunctionKeys = 16;
		pDevExt->m_attributeKeyboard.NumberOfIndicators = 1;
		pDevExt->m_attributeKeyboard.NumberOfKeysTotal = 101;
		pDevExt->m_attributeKeyboard.InputDataQueueLength = 1;
		pDevExt->m_attributeKeyboard.KeyRepeatMinimum.Rate = 2;
		pDevExt->m_attributeKeyboard.KeyRepeatMinimum.Delay = 250;
		pDevExt->m_attributeKeyboard.KeyRepeatMaximum.Rate = 30;
		pDevExt->m_attributeKeyboard.KeyRepeatMaximum.Delay = 1000;
		pDevExt->m_paramIndicator.LedFlags = 0;
		pDevExt->m_paramTypematic.Rate = 30;
		pDevExt->m_paramTypematic.Delay = 250;

		KeInitializeDpc(&pDevExt->m_dpcAutoRepeat,&AppleKeyboardAutoRepeat,pDevExt);

		KeInitializeTimer(&pDevExt->m_timerRepeat);
		pDevExt->m_llTimeRepeatDelay.QuadPart = -2500000;

		pDevExt->m_lRepeatPeriod = 0x21;
		KeInitializeDpc(&pDevExt->m_dpcInitiateStartRead,&AppleKeyboardInitiateStartRead,pDevExt);

		KeInitializeTimer(&pDevExt->m_timerRecover);
		pDevExt->m_llTimeRecover.QuadPart = -500000;
		pDevExt->m_bKeyboardProblem = 0;

		POWER_STATE state;
		state.DeviceState = PowerDeviceD0;
		PoSetPowerState(pFunctionDeviceObject,DevicePowerState,state);
		pFunctionDeviceObject->Flags |= DO_POWER_PAGABLE;
		pFunctionDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

		pDevExt->m_wmiLibContext.GuidCount = ARRAYSIZE(g_wmiGuidAppleKeyboard);
		pDevExt->m_wmiLibContext.GuidList = g_wmiGuidAppleKeyboard;
		pDevExt->m_wmiLibContext.QueryWmiRegInfo = &AppleKeyboardQueryWmiRegInfo;
		pDevExt->m_wmiLibContext.QueryWmiDataBlock = &AppleKeyboardQueryWmiDataBlock;
		pDevExt->m_wmiLibContext.SetWmiDataBlock = &AppleKeyboardSetWmiDataBlock;
		pDevExt->m_wmiLibContext.SetWmiDataItem = &AppleKeyboardSetWmiDataItem;
		pDevExt->m_wmiLibContext.ExecuteWmiMethod = 0;
		pDevExt->m_wmiLibContext.WmiFunctionControl = 0;

		bDetachDevice = bDeleteDevice = FALSE;
	}
	__finally
	{
		if(bDetachDevice)
			IoDetachDevice(pDevExt->m_pLowerDevice);

		if(bDeleteDevice)
			IoDeleteDevice(pFunctionDeviceObject);
	}

	AppleDebugPrint(DBGLEVEL_INFO,"Leave AppleKeyboardAddDevice 0x%08x\n",statusRet);

	return statusRet;
}